﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using SynoManager.GUI;

namespace SynoManager.GUI
{
    /// <summary>
    /// Class that holds all the <see cref="IGuiPlugin"/>s.
    /// </summary>
    public class PluginManager
    {
        private List<IGuiPlugin> plugins = new List<IGuiPlugin>();

        /// <summary>
        /// Initializes a new instance of the <see cref="PluginManager"/> class.
        /// </summary>
        public PluginManager()
        {
            Debug.WriteLine("Searching for GUI plugins...");
            foreach(Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                try
                {
                    foreach (Type type in assembly.GetTypes())
                    {
                        if ((!type.IsAbstract) && (!type.IsInterface) && (type.GetInterface(typeof(IGuiPlugin).Name) != null))
                        {
                            IGuiPlugin plugin = (IGuiPlugin)Activator.CreateInstance(type);
                            plugins.Add(plugin);
                        }
                    }
                }
                catch (ReflectionTypeLoadException ex)
                {
                    Debug.WriteLine("ReflectionTypeLoadException: " + ex.Message);
                }
            }
            Debug.Assert(plugins.Count > 0, "No plugins found");
            Debug.WriteLine(plugins.Count + " plugins found", "PluginManager");
            plugins.Sort((left, right) => left.TabPriority.CompareTo(
                                              right.TabPriority));
        }

        /// <summary>
        /// Initializes all plugins with the specified device.
        /// </summary>
        /// <param name="device">The device.</param>
        /// <remarks>
        ///     <para>This function calls the <seealso cref="IGuiPlugin.Initialize(SynoDevice)"/> method on all loaded plugins.</para>
        /// </remarks>
        public void Initialize(SynoDevice device)
        {
            foreach(var plugin in plugins)
            {
                plugin.Initialize(device);
            }
        }

        /// <summary>
        /// Function that is called when the connection state has changed
        /// </summary>
        /// <param name="isConnected">Returns true if the device is connected.</param>
        /// <param name="wasConnected">Returns true if the device has successfully connected in the past</param>
        /// <remarks>This function should be called in a thread-safe way, so no Invoke is required.</remarks>
        public void ConnectionStateChange(bool isConnected, bool wasConnected)
        {
            foreach(var plugin in plugins)
            {
                plugin.OnConnectionStateChange(isConnected, wasConnected);
            }
        }

        /// <summary>
        /// Get the list of plugins
        /// </summary>
        public IEnumerable<IGuiPlugin> Plugins
        {
            get { return plugins;}
        }

        /// <summary>
        /// Initialize all plugins with the specified <see cref="IHost" /> window
        /// </summary>
        /// <param name="host">Host window for all plugins</param>
        /// <remarks>This function calls the <seealso cref="IGuiPlugin.InitializeHost(IHost)" /> method on all loaded plugins.</remarks>
        public void SetHost(IHost host)
        {
            foreach(var plugin in plugins)
            {
                plugin.InitializeHost(host);
            }
        }
    }
}
